
Security News
Deno 2.2 Improves Dependency Management and Expands Node.js Compatibility
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
control your react component state in a funny way, every react instance of different class if they were registered in concent own the ability of knowing and syncing each other's state, just have a try and discover more^_^
English | 简体中文
a predictable、zero-cost-use、progressive、high performance's enhanced state management solution,work based on dependency mark、ref collection and state broadcast,power you react!
visit official website https://concentjs.github.io/concent-doc to learn more.
run
to load model configuration, use register
to decorate class component, or use useConcent
in function component。Provider
any more, the decorated component can be interactive with store by setState
directly.;hello-concentsetState
, you can also use dispatch
or invoke
to change state, separate your business logic and ui completely.。from class to functionrun
, user can also call configure
api to configure you model definition near your component, that means you can publish your component to npm with your component model。Details see here react-router-concent,expose history
,you can call it anywhere in your app to enjoy the imperative navigation jump.
react-router-concent online demo
Details see here concent-plugin-redux-devtool,track your state changing history。
Details see here concent-plugin-loading,control all your reducer function's loading status easily。
concent-plugin-loading online demo
Make sure you have installed nodejs。
In your computer,use create-react-app to create an app
$ npm i -g create-react-app
$ create-react-app cc-app
After app created,go to the app's root directory,install concent
with npm command.
$ cd cc-app
$ npm i --save concent
or yarn command
$ yarn add concent
you can also review the online example's file
App1-module-state.js
content, and copy it to fileApp.js
to see the effect.
import React, { Component } from 'react';
import { register, run, useConcent } from 'concent';
// run concent with a module named counter
run({
counter:{
state:{count:1}
}
})
// define a class component that belong to 'counter' module
@register('counter')
class Counter extends Component{
render(){
// now setState can commit state to store and broadcast state to other refs which also belong to counter module
const add = ()=>this.setState({count:this.state.count+1});
return (
<div>
{this.state.count}
<button onClick={add}>add</button>
</div>
)
}
}
// define a function component that belong to 'counter' module
function FnCounter(){
const ctx = useConcent('counter');
const add = ()=>ctx.setState({count:ctx.state.count+1});
return (
<div>
{ctx.state.count}
<button onClick={add}>add</button>
</div>
)
}
export default function App() {
return (
<div className="App">
<Counter />
<FnCounter />
</div>
);
}
import React, { Component, Fragment } from 'react';
import { register, run } from 'concent';
run({
counter: {// define counter module
state: {// 【necessary】,define state
count: 0,
products: [],
type: '',
},
reducer: {// 【optional】define reducer,write logic code to change the state
inc(payload=1, moduleState) {
return { count: moduleState.count + payload };
},
dec(payload=1, moduleState) {
return { count: moduleState.count - payload };
},
async inc2ThenDec3(payload, moduleState, actionCtx){
await actionCtx.dispatch('inc', 2);
await actionCtx.dispatch('dec', 3);
}
},
computed:{// 【optional】define computed,the function will be triggered when stateKey changed,and the return result will be cached.
count(newState, oldState){
return newState.count * 2;
}
},
watch:{// 【optional】define watch,the function will be triggered when stateKey changed,usually for some async tasks
count(newState, oldState){
console.log(`count changed from ${oldState.count} to ${newState.count}`);
}
},
init: async ()=>{//【optional】async state init process, attention this process has nothing to do with whether the component is mounted or not, but the result can effect all the components belong to this module.
const state = await api.fetchState();
return state;
}
}
})
recommend user put every part of model configure to separate files,because they have clear responsibilities.
|____models # business models
| |____index.js
| |____counter
| | |____index.js
| | |____reducer.js # change state methods(optional)
| | |____computed.js # computed methods(optional)
| | |____watch.js # watch methods(optional)
| | |____init.js # async state initialization function(optional)
| | |____state.js # module init state(required)
now reducer functions can call each other with function ref directly(not only string)
export function inc(payload=1, moduleState) {
return { count: moduleState.count + payload };
}
export function dec(payload=1, moduleState) {
return { count: moduleState.count - payload };
}
// combine other reducer functions to complete a logic
export async function inc2ThenDec3(payload, moduleState, actionCtx){
await actionCtx.dispatch(inc, 2);
await actionCtx.dispatch(dec, 3);
}
you can also call setState
in reducer function block, it is a promisified api.
export updateLoading(loading){
return { loading }
}
export async function inc2ThenDec3(payload, moduleState, actionCtx){
await actionCtx.dispatch(inc, 2);
//equivalent actionCtx.dispatch(updateLoading, true);
await actionCtx.setState({loading: true});
await actionCtx.dispatch(dec, 3);
//equivalent actionCtx.dispatch(updateLoading, false);
await actionCtx.setState({loading: false});
//if you return a new partial state here, it will trigger view updated also, but this is optional.
return { tip: 'you can return some new value in current reducer fn ot not' };
}
const setup = ctx => {
console.log('setup only execute one time before first render period');
ctx.on('someEvent', (p1, p2)=> console.log('receive ', p1, p2));
ctx.effect(() => {
fetchProducts();
}, ["type", "sex", "addr", "keyword"]);//only pass state key
/** equivalent code below in function component
useEffect(() => {
fetchProducts(type, sex, addr, keyword);
}, [type, sex, addr, keyword]);
*/
ctx.effect(() => {
return () => {
// clear up
// equivalent componentWillUnmout
};
}, []);// pass zero length array, to let effect only execute one time after first render period
/** equivalent code below in function component
useEffect(()=>{
return ()=>{
// clear up
}
}, []);
*/
ctx.effectProps(() => {
// write effect handler for props value change,it is different with ctx.effect which works for state value changing
const curTag = ctx.props.tag;
if (curTag !== ctx.prevProps.tag) ctx.setState({ tag: curTag });
}, ["tag"]);//only pass props key
/** equivalent code below in function component
useEffect(()=>{
if(tag !== propTag)setTag(tag);
}, [propTag, tag]);
*/
// define ref computed, the function will been triggered when count changed, user can get the function result from ctx.refComputed.doubleTen later in render block
ctx.computed('doubleTen', (newState, oldState)=>{
return newState.count * 10;
}, ['count']);
// but mostly you should think about module computed first if you want to share the computed logic between all refs and only want the computed function only been triggered one time when state state changed, cause every ref will trigger its own computed function;
// if retKey is equal to stateKey, you can write like below
ctx.computed('count', ({count})=>count*2);
// define ref watch, and just like reason of module computed, you should think about module watch first
ctx.watch('retKey', ()=>{}, ['count']);
const fetchProducts = () => {
const { type, sex, addr, keyword } = ctx.state;
api.fetchProducts({ type, sex, addr, keyword })
.then(products => ctx.setState({ products }))
.catch(err => alert(err.message));
};
const inc = () => {
ctx.setState({ count: this.state.count + 1 });
}
const dec = () => {
ctx.setState({ count: this.state.count - 1 });
}
//dispatch can commit state to store, and broadcast state to other refs(which belongs to module counter) also
const incD = () => {
ctx.dispatch('inc');// or better way: this.ctx.moduleReducer.inc()
}
const decD = () => {
ctx.dispatch('dec');// or better way: this.ctx.moduleReducer.dec()
}
// return result will been collected to ctx.settings
return {
inc,
dec,
incD,
decD,
fetchProducts,
//sync type value, sync method can extract value from event automatically
changeType: ctx.sync('type'),
};
};
// base on class
@register({module:'counter', setup})
class Counter extends Component {
constructor(props, context){
super(props, context);
this.state = {tag: props.tag};// private state
}
render() {
// now the state is a combination of private state and module state
const { count, products, tag } = this.state;
// this.state can replace with this.ctx.state
//const { count, products, tag } = this.ctx.state;
const {inc, dec, indD, decD, fetchProducts, changeType} = this.ctx.settings;
return 'your ui xml...';
}
}
// base on renderProps
const PropsCounter = registerDumb({module:'counter', setup})(ctx=>{
const { count, products, tag } = ctx.state;
const {inc, dec, indD, decD, fetchProducts, changeType} = ctx.settings;
return 'your ui xml...';
});
// base on hook
function HookCounter(){
const ctx = useConcent({module:'counter', setup});
const { count, products, tag } = ctx.state;
const {inc, dec, indD, decD, fetchProducts, changeType} = ctx.settings;
return 'your ui xml...';
}
FAQs
Build-in dependency collection, a predictable、zero-cost-use、progressive、high performance's react develop framework
The npm package concent receives a total of 56 weekly downloads. As such, concent popularity was classified as not popular.
We found that concent demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 0 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Security News
Deno 2.2 enhances Node.js compatibility, improves dependency management, adds OpenTelemetry support, and expands linting and task automation for developers.
Security News
React's CRA deprecation announcement sparked community criticism over framework recommendations, leading to quick updates acknowledging build tools like Vite as valid alternatives.
Security News
Ransomware payment rates hit an all-time low in 2024 as law enforcement crackdowns, stronger defenses, and shifting policies make attacks riskier and less profitable.